// import api from '@/api'
import api from '../../api/index';
//session信息
const EMPTY_SESSION = () => ({
    username: null,
    scope: '',
    expires: 0,
    access_token: '',
    refresh_token: '',
    token_type: 'bearer',
    jti: '',

    //客户端自定义信息
    rememberMe: false
})

//账号信息
const EMPTY_ACCOUNT = () => ({
    id: null,
    username: null,
    name: '',
    avatar: '',
    telephone: '',
    email: '',
    location: ''
})

//如果是本地存储有缓存的Session信息，启动时候尝试从该信息中恢复
//这里采用 Object.assign主要是为了对服务端做一个容错，以便客户端以来的所有属性都至少有一个默认值，而不会出现服务端未返回时候返回的unddfined
//注意：将JWT存储在sessionStorage或者localStorage中式存在XSS风险的
const state = {
    
 
    session :api.option.hasSession?Object.assign(EMPTY_SESSION(), api.option.getSession()) : EMPTY_SESSION(),
    account: EMPTY_ACCOUNT(),
    
    //收藏夹，只存在本地，暂时没什么用
    favorite: []
}

const getters = {
    /**
     * 检查授权是否有效，
     *生效要求：持有jwt令牌，且并未超出令牌期限
     */
    isAuthorized: state => !!state.session.access_token && (state.session.expires > new Date().getTime()),
    /**
     * 检查是否时管理员
     * 生效要求：已获得登录授权，并且角色中存在Role_admin
     * 
     */
    isAdministrator: (state, getters) => getters.isAuthorized && state.session.authorities.includes('ROLE_ADMIN')
}


const mutations = {

    /**
     * 
     * 登录成功，设置登录状态
     * 
     * @param state
     * @param session 客户端的Session
     * 
     * 服务端不存储状态，登录成功后用户状态信息通过JWT返回浏览器，存储在客户端的Session中，其结构为：
     * {username,scope,expires,access_token,refresh_token,token_type,jti}
     * 另外，根据用户在客户端登录的选项，一下内容也被添加到客户端Session中：
     * {rememberMe,location地点},其实客户端session中也可以存储状态信息，然后渲染?
     * 
     */
    setupSession(state, session) {
        //服务器端传来的session过期时间是相对时间（因为服务器，客户端的时间可能不一致），存储在本地时候，
        //转化为绝对时间戳

        //注意服务端返回的时间单位是秒，客户端的时间戳是毫秒
        session.expires = new Date().getTime() + (session.expires_in * 1000)
        /**
         * 
         * 为什么要把session状态存储到常量里的同时，放在localstory里嘞
         * 在js和在本地缓存的区别是什么？
         * 
         */
        Object.assign(state.session, session)
        api.option.setSession(session)

    },

    /**
     * 退出登录状态
     * 清理vuex中所有的状态，以及本地存储中的Session
     * 
     */
    clearSession(state) {
        state.session = EMPTY_SESSION()
        state.session = EMPTY_ACCOUNT()
        api.option.clearSession()
    }

}


const actions = {
    /**
     * 根据过期时间书信OAuth令牌的触发器
     * 
     */
    refreshSessionTrigger({ dispatch, commit, state }) {
        //session具有时效性，设置更新令牌的触发器
        let timeout = state.session.expires - new Date().getTime()
        if (timeout > 0) {
            console.log(`Session将在：${timeout}毫秒后过期，届时会重刷新令牌`)
            setTimeout(() => {
                dispatch('refreshSession', { commit, state }).then(() => {
                    dispatch('refreshSessionTr igger', { commit, state })
                })
            }, timeout)
        }
    },

    /**
 * 向服务端请求新的访问令牌
 */
    async refreshSession({ commit, state }) {
        try {
            let { data } = await api.auth.refresh(state.session.refresh_token)
            commit('setupSession', data)
        } catch (e) {
            // 刷新失败，就清理掉当前的用户
            commit('clearSession')
        }

    }
}

export default{
    namespaced:true,
    state,
    getters,
    mutations,
    actions
}
